import asyncio
import logging
from typing import List, Optional
from dataclasses import dataclass
import os
from dotenv import load_dotenv

@dataclass
class GitResult:
    """Git命令执行结果"""
    success: bool
    message: str
    code: int = 0

class GitCmd:
    """Git命令行工具类"""
    
    def __init__(self, repo_path: str = None):
        """初始化Git命令行工具"""
        load_dotenv()
        self.repo_path = repo_path or os.getenv('CODE_PATH')
        self.owner = os.getenv('GITEE_OWNER')
        self.repo = os.getenv('GITEE_REPO')
        self.token = os.getenv('GITEE_ACCESS_TOKEN')
        
        if not all([self.repo_path, self.owner, self.repo, self.token]):
            raise ValueError("请确保设置了所有必需的环境变量: CODE_PATH, GITEE_OWNER, GITEE_REPO, GITEE_ACCESS_TOKEN")
        
        if not os.path.exists(self.repo_path):
            raise ValueError(f"仓库路径无效: {self.repo_path}")
            
        self.remote_url = f"https://{self.token}@gitee.com/{self.owner}/{self.repo}.git"
        
    async def _run_cmd(self, cmd: str) -> GitResult:
        """执行Git命令"""
        try:
            process = await asyncio.create_subprocess_shell(
                cmd,
                cwd=self.repo_path,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await process.communicate()
            
            if process.returncode != 0:
                return GitResult(
                    success=False,
                    message=stderr.decode(),
                    code=process.returncode
                )
            
            return GitResult(
                success=True,
                message=stdout.decode(),
                code=0
            )
            
        except Exception as e:
            return GitResult(
                success=False,
                message=str(e),
                code=-1
            )
    
    async def init(self) -> GitResult:
        """初始化Git仓库"""
        return await self._run_cmd('git init')
    
    async def add(self, files: str = ".") -> GitResult:
        """添加文件到暂存区"""
        return await self._run_cmd(f'git add {files}')
    
    async def commit(self, message: str) -> GitResult:
        """提交更改"""
        return await self._run_cmd(f'git commit -m "{message}"')
    
    async def push(self, remote: str = "origin", branch: str = "master") -> GitResult:
        """推送到远程仓库"""
        return await self._run_cmd(f'git push -u {remote} {branch}')
    
    async def setup_remote(self, url: str, name: str = "origin") -> GitResult:
        """设置远程仓库"""
        return await self._run_cmd(f'git remote add {name} {url}')
    
    async def pull(self, remote: str = "origin", branch: str = "master") -> GitResult:
        """从远程仓库拉取更改"""
        return await self._run_cmd(f'git pull {remote} {branch}')

    async def force_push(self, remote: str = "origin", branch: str = "master") -> GitResult:
        """强制推送到远程仓库（谨慎使用）"""
        return await self._run_cmd(f'git push -f {remote} {branch}')

    async def ensure_git_setup(self) -> List[GitResult]:
        """确保Git仓库已正确设置"""
        results = []
        
        # 检查是否已初始化
        if not os.path.exists(os.path.join(self.repo_path, '.git')):
            logging.info("初始化Git仓库...")
            results.append(await self.init())
            
        # 检查远程仓库
        check_remote = await self._run_cmd('git remote -v')
        if 'origin' not in check_remote.message:
            logging.info("设置远程仓库...")
            results.append(await self.setup_remote(self.remote_url))
            
        return results

    async def upload_to_gitee(self, commit_msg: str = None, repo_path: str = None) -> List[GitResult]:
        """一键上传到Gitee"""
        if repo_path:
            self.repo_path = repo_path
            
        commit_msg = commit_msg or os.getenv('CODE_COMMIT_MESSAGE', 'Update from MCP')
        results = []
        
        # 确保Git设置正确
        setup_results = await self.ensure_git_setup()
        results.extend(setup_results)
        
        logging.info(f"开始上传代码到 {self.owner}/{self.repo}")
        
        # 执行Git操作
        operations = [
            (self.add, "添加文件"),
            (self.commit, [commit_msg], "提交更改"),
            (self.push, [], "推送到远程")
        ]
        
        for op in operations:
            if len(op) == 3:
                func, args, desc = op
            else:
                func, desc = op
                args = []
            
            logging.info(f"执行: {desc}")
            result = await func(*args)
            results.append(result)
            
            if not result.success:
                logging.error(f"{desc}失败: {result.message}")
                if "non-fast-forward" in result.message:
                    logging.warning("尝试强制推送...")
                    results.append(await self.force_push())
                break
                
        return results

# 更新测试代码
async def test_git_upload(repo_path: str = None, commit_msg: str = None):
    git = GitCmd(repo_path)
    print(f"开始上传代码... 路径: {git.repo_path}")
    results = await git.upload_to_gitee(commit_msg)
    
    for i, result in enumerate(results, 1):
        status = "成功" if result.success else "失败"
        print(f"步骤 {i} {status}: {result.message.strip()}")

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(test_git_upload())
